package com.uobgroup.ews.uam.web;

import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.uobgroup.ews.uam.core.domain.AccessControl;
import com.uobgroup.ews.uam.core.domain.CombinationMatrix;
import com.uobgroup.ews.uam.core.domain.CombinationType;
import com.uobgroup.ews.uam.core.domain.Reference;
import com.uobgroup.ews.uam.core.model.CombiSecInfoList;
import com.uobgroup.ews.uam.core.model.CombinationACLParamsName;
import com.uobgroup.ews.uam.core.service.AccessControlService;
import com.uobgroup.ews.uam.core.service.CombinationACLService;
import com.uobgroup.ews.uam.core.service.CombinationMatrixService;
import com.uobgroup.ews.uam.core.service.ReferenceService;
import com.uobgroup.ews.uam.core.service.SecurityGroupService;

@RequestMapping("/combinationmatrixes")
@Controller
public class CombinationMatrixController {

   @Autowired
   AccessControlService accessControlService;

   @Autowired
   ReferenceService referenceService;

   @Autowired
   SecurityGroupService securityGroupService;

   @Autowired
   CombinationMatrixService combinationMatrixService;

   @Autowired
   CombinationACLService combinationACLService;

   @Autowired
   private ReloadableResourceBundleMessageSource messageSource;

   private boolean isShow = true;
   
   @RequestMapping(method = RequestMethod.POST, produces = "text/html")
   public String create(@Valid CombinationMatrix combinationMatrix, BindingResult bindingResult, Model uiModel,
         HttpServletRequest httpServletRequest, Principal principal) {
      if (bindingResult.hasErrors()) {
         populateCreateForm(uiModel, combinationMatrix);
         return "combinationmatrixes/create";
      }
      if (combinationMatrixService.isPropertiesExisted(combinationMatrix)) {
         populateCreateForm(uiModel, combinationMatrix);
         uiModel.addAttribute("messageError", messageSource.getMessage("field_unique", new String[] { "the Combination Matrix" }, null));
         return "combinationmatrixes/create";
      }
      else {
         uiModel.asMap().clear();
         combinationMatrix.setLastModificationUserId(principal.getName());
         combinationMatrixService.save(combinationMatrix);
         return "redirect:/combinationmatrixes/view/"
               + encodeUrlPathSegment(combinationMatrix.getId().toString(), httpServletRequest);
      }
      
   }

   @RequestMapping(value = "/search/accesscontrols", method = RequestMethod.GET, produces = "text/html")
   public String searchForm(Model uiModel) {
      uiModel.addAttribute("accessControl", new AccessControl());
      return "combinationmatrixes/accesscontrolSearch";
   }

   @RequestMapping(value = "/search/accesscontrols", method = RequestMethod.POST)
   public String search(AccessControl accessControl, Model uiModel) {
      List<AccessControl> accessControls = null;
      String name = accessControl.getName();
      if (name != null && name.trim().length() > 0)
         accessControls = accessControlService.findAccessControlbyLikeName(accessControl.getName());
      else
         accessControls = accessControlService.findAllAccessControls();

      uiModel.addAttribute("accessControls", accessControls);
      return "combinationmatrixes/ACLSearchResult";
   }

   @RequestMapping(value = "/search/accesscontrols/selected", method = RequestMethod.POST)
   public String search(@Param("idsSelected") String idsSelected, Model uiModel) {
      List<AccessControl> accessControls = new ArrayList<AccessControl>();
      if (idsSelected != null && idsSelected.trim().length() > 0) {
         String[] idStrs = idsSelected.split("\\|");
         List<Long> ids = new ArrayList<Long>();
         for (String idStr : idStrs) {
            if (!("".equalsIgnoreCase(idStr))) {
               ids.add(Long.parseLong(idStr));
            }
         }
         accessControls = accessControlService.findAllAccessControlsbyInIds(ids);
      }
      uiModel.addAttribute("accessControls", accessControls);
      return "combinationmatrixes/ACLSelected";
   }

   @RequestMapping(value = "/create", produces = "text/html", method = RequestMethod.GET)
   public String createForm(Model uiModel) {
      populateCreateForm(uiModel, new CombinationMatrix());
      return "combinationmatrixes/create";
   }

   @RequestMapping(value = "/view/{id}", produces = "text/html")
   public String show(@PathVariable("id") Long id, Model uiModel) {
      if (isShow == false && combinationMatrixService.isCombinationInUse(id)) {
         uiModel.addAttribute("messageError",
               messageSource.getMessage("field_cannot_update", new Object[] { "this combination matrix" }, null));
         isShow = true;
      }
      addDateTimeFormatPatterns(uiModel);
      uiModel.addAttribute("combinationmatrix", combinationMatrixService.findbyId(id));
      uiModel.addAttribute("itemId", id);
      return "combinationmatrixes/show";
   }

   @RequestMapping(produces = "text/html")
   public String list(@RequestParam(value = "page", required = false) Integer page,
         @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
      //if (page != null || size != null) {
         int sizeNo = size == null ? 10 : size.intValue();
         final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
         uiModel.addAttribute("combinationmatrixes", combinationMatrixService.findEntries(firstResult, sizeNo));
         float nrOfPages = (float) combinationMatrixService.count() / sizeNo;
         uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
               : nrOfPages));
      /*}
      else {
         uiModel.addAttribute("combinationmatrixes", combinationMatrixService.findAll());
      }*/
      addDateTimeFormatPatterns(uiModel);
      return "combinationmatrixes/list";
   }

   @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
   public String update(@Valid CombinationMatrix combinationMatrix, BindingResult bindingResult, Model uiModel,
         HttpServletRequest httpServletRequest, Principal principal) {
      if (bindingResult.hasErrors()) {
         populateEditForm(uiModel, combinationMatrix);
         return "combinationmatrixes/update";
      }

      if (!combinationMatrixService.isCombinationInUse(combinationMatrix.getId())) {
         if (!combinationMatrixService.isPropertiesExisted(combinationMatrix)){
            uiModel.asMap().clear();
            combinationMatrix.setLastModificationUserId(principal.getName());
            combinationMatrixService.update(combinationMatrix);
         }
      }

      isShow = false;
      return "redirect:/combinationmatrixes/view/"
            + encodeUrlPathSegment(combinationMatrix.getId().toString(), httpServletRequest);
   }

   @RequestMapping(value = "/update/{id}", produces = "text/html", method = RequestMethod.GET)
   public String updateForm(@PathVariable("id") Long id, Model uiModel) {
      populateEditForm(uiModel, combinationMatrixService.findbyId(id));
      return "combinationmatrixes/update";
   }

   @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "text/html")
   public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page,
         @RequestParam(value = "size", required = false) Integer size, Model uiModel, Principal principal) {
      if (!combinationMatrixService.isCombinationInUse(id)) {
         CombinationMatrix combinationMatrix = combinationMatrixService.findbyId(id);
         combinationMatrix.setLastModificationUserId(principal.getName());
         combinationMatrixService.delete(combinationMatrix);
         //combinationMatrixService.deleteById(id);
      }
      else {
         uiModel.addAttribute("messageError", messageSource.getMessage("field_cannot_delete", new Object[] {}, null));
         //if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
            uiModel.addAttribute("combinationmatrixes", combinationMatrixService.findEntries(firstResult, sizeNo));
            float nrOfPages = (float) combinationMatrixService.count() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
                  : nrOfPages));
         /*}
         else {
            uiModel.addAttribute("combinationmatrixes", combinationMatrixService.findAll());
         }*/
         return "combinationmatrixes/list";
      }

      uiModel.asMap().clear();
      uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
      uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
      return "redirect:/combinationmatrixes";
   }

   @RequestMapping(method = RequestMethod.GET, value = "/getDocSecurity", headers = "Accept=application/json")
   public @ResponseBody
   CombiSecInfoList getCombiDocSec(@RequestParam(value = "doctype", required = true) String doctype,
         @RequestParam(value = "country", required = true) String country,
         @RequestParam(value = "processingcenter", required = false) String processingcenter,
         @RequestParam(value = "transactiontype", required = false) String transactiontype,
         @RequestParam(value = "producttype", required = false) String producttype,
         @RequestParam(value = "userlocation", required = false) String userlocation) {

      HashMap<String, List<String>> params = buildCombinationParams(doctype, country, processingcenter,
            transactiontype, producttype, userlocation);

      return combinationACLService.getDocSecurity(params);
   }

   @RequestMapping(method = RequestMethod.GET, value = "/getCaseSecurity", headers = "Accept=application/json")
   public @ResponseBody
   CombiSecInfoList getCombiCaseSec(@RequestParam(value = "doctype", required = false) String doctype,
         @RequestParam(value = "country", required = true) String country,
         @RequestParam(value = "processingcenter", required = true) String processingcenter,
         @RequestParam(value = "transactiontype", required = true) String transactiontype,
         @RequestParam(value = "producttype", required = false) String producttype,
         @RequestParam(value = "userlocation", required = false) String userlocation) {

      HashMap<String, List<String>> params = buildCombinationParams(doctype, country, processingcenter,
            transactiontype, producttype, userlocation);

      return combinationACLService.getCaseSecurity(params);
   }

   private HashMap<String, List<String>> buildCombinationParams(String docType, String country,
         String processingCenter, String transactionType, String productType, String userLocation) {
      HashMap<String, List<String>> params = new HashMap<String, List<String>>();

      buildCombiParam(CombinationACLParamsName.DOC_TYPE, docType, params);
      buildCombiParam(CombinationACLParamsName.COUNTRY, country, params);
      buildCombiParam(CombinationACLParamsName.PROCESSING_CENTER, processingCenter, params);
      buildCombiParam(CombinationACLParamsName.TRANSACTION_TYPE, transactionType, params);
      buildCombiParam(CombinationACLParamsName.PRODUCT_TYPE, productType, params);
      buildCombiParam(CombinationACLParamsName.USER_LOCATION, userLocation, params);

      return params;
   }

   private void buildCombiParam(String key, String param, HashMap<String, List<String>> params) {
      int len = 0;
      if (param != null) {
         List<String> values = new ArrayList<String>();
         String[] paramArr = param.split(",");
         len = paramArr.length;
         for (int i = 0; i < len; i++) {
            values.add(paramArr[i]);
         }
         params.put(key, values);
      }
   }

   void addDateTimeFormatPatterns(Model uiModel) {
      uiModel.addAttribute("combinationMatrix_modificationdate_date_format",
            DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
   }

   void populateEditForm(Model uiModel, CombinationMatrix combinationMatrix) {
      uiModel.addAttribute("combinationMatrix", combinationMatrix);
      addDateTimeFormatPatterns(uiModel);
      uiModel.addAttribute("combinationtypes", Arrays.asList(CombinationType.values()));
      uiModel.addAttribute("countrys", referenceService.findAllCountrys());

      uiModel.addAttribute("documenttypes", referenceService.findAllDocumentTypes());
      uiModel.addAttribute("processingcentres", referenceService.findAllProcessingCenters());
      uiModel.addAttribute("transactiontypes", referenceService.findAllTransactionTypes());

      List<Reference> lstProd = referenceService.findAllProductTypes();
      lstProd.add(0, new Reference());
      uiModel.addAttribute("producttypes", lstProd);
      List<Reference> lstLoc = referenceService.findAllUserLocations();
      lstLoc.add(0, new Reference());
      uiModel.addAttribute("locations", lstLoc);
   }

   void populateCreateForm(Model uiModel, CombinationMatrix combinationMatrix) {
      uiModel.addAttribute("combinationMatrix", combinationMatrix);
      addDateTimeFormatPatterns(uiModel);
      uiModel.addAttribute("combinationtypes", Arrays.asList(CombinationType.values()));
      uiModel.addAttribute("countrys", referenceService.findAllCountrys());
      uiModel.addAttribute("documenttypes", referenceService.findAllDocumentTypes());
      uiModel.addAttribute("processingcentres", referenceService.findAllProcessingCenters());
      uiModel.addAttribute("producttypes", referenceService.findAllProductTypes());
      uiModel.addAttribute("transactiontypes", referenceService.findAllTransactionTypes());
      uiModel.addAttribute("locations", referenceService.findAllUserLocations());
   }

   String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
      String enc = httpServletRequest.getCharacterEncoding();
      if (enc == null) {
         enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
      }
      try {
         pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
      }
      catch (UnsupportedEncodingException uee) {
      }
      return pathSegment;
   }
}
